package com.tinusgraglin.enclusiv.ui.screens

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.tinusgraglin.enclusiv.*
import com.tinusgraglin.enclusiv.R
import com.tinusgraglin.enclusiv.ui.components.*
import com.tinusgraglin.enclusiv.ui.theme.*
import com.tinusgraglin.enclusiv.datalayer.Exceptions.*
import com.tinusgraglin.enclusiv.ui.EnclusivViewModelFactory
import com.tinusgraglin.enclusiv.ui.viewmodel.SignUpActivityViewModel
import kotlinx.coroutines.launch

@OptIn(ExperimentalComposeUiApi::class)
class SignUpActivity : ComponentActivity() {
    private val viewModel: SignUpActivityViewModel by viewModels {
        EnclusivViewModelFactory()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            EnclusivTheme {
                val navController = rememberNavController()

                NavHost(navController = navController, startDestination = "idFillUp") {
                    composable("idFillUp") {
                        IdentificationFillUpScreen(navController = navController)
                    }
                    composable(route = "verify?email={emailStr}",
                        arguments = listOf(navArgument("emailStr") {})
                    ) {
                        VerificationScreen(navController = navController, it.arguments!!.getString("emailStr")!!)
                    }
                    composable(route = "pwdFillUp?email={emailStr}",
                        arguments = listOf(navArgument("emailStr") {})
                    ) {
                        PasswordScreen(navController = navController, it.arguments!!.getString("emailStr")!!)
                    }
                }
            }
        }

    }

    @Composable
    fun NextButton(
        enabled: Boolean,
        modifier: Modifier,
        isLoading: Boolean = false,
        onClick: () -> Unit,
    ) {
        Button(
            enabled = enabled,
            modifier = modifier,
            onClick = onClick,
            shape = RoundedCornerShape(50)
        ) {
            if (isLoading) {
                AnimatedLoadingDots(modifier = Modifier.wrapContentSize(), color = PurpleMain)
            } else {
                Text (
                    text = stringResource(R.string.ui_next),
                    fontSize = 18.sp,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }

    @Composable
    fun HeadText(
        text: String,
        size: TextUnit = 32.sp
    ) {
        Text(
            text = text,
            modifier = Modifier
                .fillMaxWidth(0.8F)
                .wrapContentHeight(),
            fontSize = size,
            fontWeight = FontWeight.Bold,
            textAlign = TextAlign.Left
        )
    }

    @Composable
    fun NeckText(
        text: String,
        size: TextUnit = 14.sp
    ) {
        Text(
            text = text,
            modifier = Modifier
                .fillMaxWidth(0.8F)
                .wrapContentHeight(),
            fontSize = size,
            fontWeight = FontWeight.Light,
            textAlign = TextAlign.Left
        )
    }

    @Composable
    fun IdentificationFillUpScreen(navController: NavController) {
        val keyboardController = LocalSoftwareKeyboardController.current

        var email by rememberSaveable { mutableStateOf("") }
        var validEmail by rememberSaveable { mutableStateOf(false) }
        var isRequestingEmailVerify by rememberSaveable { mutableStateOf(false) }
        var showAlert by rememberSaveable { mutableStateOf(false) }
        val scope = rememberCoroutineScope()

        val onNext = {
            keyboardController?.hide()
            isRequestingEmailVerify = true

            val deferred = viewModel.verifyEmailAsync(email)

            scope.launch {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    try {
                        deferred.await()
                        navController.navigate("verify?email=${email}")
                    }catch (e: Exception) {
                        showAlert = true
                    } finally {
                        isRequestingEmailVerify = false
                    }
                }
            }
        }

        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colors.background
        ) {
            Column(horizontalAlignment = Alignment.CenterHorizontally) {
                Spacer(Modifier.height(60.dp))
                HeadText(text = stringResource(R.string.ui_sign_up))
                Spacer(Modifier.height(4.dp))
                NeckText(text = stringResource(R.string.ui_signup_id_fillup_neck_text))
                Spacer(Modifier.height(20.dp))
                EmailField(
                    enabled = !isRequestingEmailVerify,
                    value = email,
                    onValueChange = {
                        email = it
                        validEmail =
                            if (email.length < 3) false else Util.isEmailAddress(email)
                    },
                    modifier = Modifier
                        .fillMaxWidth(0.8F)
                        .wrapContentHeight(),
                    textStyle = TextStyle(fontSize = 16.sp),
                    onKeyBoardActionDone = {
                        onNext()
                    }
                )
                Spacer(Modifier.height(20.dp))
                NextButton(
                    enabled = validEmail && !isRequestingEmailVerify,
                    modifier = Modifier
                        .fillMaxWidth(0.8F)
                        .wrapContentHeight(),
                    isLoading = isRequestingEmailVerify
                ) {
                    onNext()
                }
            }
            if (showAlert) {
                SimpleConfirmAlertDialog(msg = getString(R.string.msg_abnormal_exception)) {
                    showAlert = false
                }
            }
        }
    }

    @Composable
    fun VerificationScreen(navController: NavController, email: String) {
        val keyboardController = LocalSoftwareKeyboardController.current

        var verificationCode by rememberSaveable { mutableStateOf("") }
        var isVerifyingCode by rememberSaveable { mutableStateOf(false) }
        var showAlert by rememberSaveable { mutableStateOf(false) }
        var alertMsg = ""
        val scope = rememberCoroutineScope()

        val resendCode = suspend {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                val resentDeferred = viewModel.verifyEmailAsync(email)
                try {
                    resentDeferred.await()
                } catch (e: Exception) {
                    alertMsg = getString(R.string.msg_abnormal_exception)
                    showAlert = true
                }
            }
        }

        val onNext = {
            keyboardController?.hide()
            isVerifyingCode = true

            val deferred = viewModel.verifyCodeAsync(email, verificationCode)

            scope.launch {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    try {
                        deferred.await()
                        navController.navigate("pwdFillUp?email=${email}")
                    } catch (cnm: VerificationCodeNotMatch) {
                        alertMsg = getString(R.string.msg_signup_wrong_code)
                        showAlert = true
                    } catch (ene: VerificationEntryNotExist) {
                        launch {
                            resendCode()
                        }
                        alertMsg = getString(R.string.msg_signup_code_expired)
                        showAlert = true
                    } catch (e: Exception) {
                        alertMsg = getString(R.string.msg_abnormal_exception)
                        showAlert = true
                    } finally {
                        isVerifyingCode = false
                    }
                }
            }
        }

        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colors.background
        ) {
            Column(horizontalAlignment = Alignment.CenterHorizontally) {
                Spacer(Modifier.height(60.dp))
                HeadText(text = stringResource(R.string.ui_signup_verify_your_email))
                Spacer(Modifier.height(4.dp))
                NeckText(text = stringResource(R.string.ui_signup_verify_email_neck_text))
                Spacer(Modifier.height(20.dp))

                OutlinedTextField(
                    enabled = !isVerifyingCode,
                    value = verificationCode,
                    label = { Text(text = stringResource(R.string.ui_text_field_verification_code)) },
                    modifier = Modifier
                        .fillMaxWidth(0.8F)
                        .wrapContentHeight(),
                    onValueChange = {
                        verificationCode =
                            if (it.length > 6) it.dropLast(it.length - 6) else it
                    },
                    singleLine = true,
                    textStyle = TextFieldStyle,
                    shape = RoundedCornerShape(50),
                    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
                    keyboardActions = KeyboardActions(onDone = {
                        onNext()
                    })
                )

                Spacer(Modifier.height(20.dp))

                NextButton(
                    enabled = verificationCode.length == 6 && !isVerifyingCode,
                    modifier = Modifier
                        .fillMaxWidth(0.8F)
                        .wrapContentHeight(),
                    isLoading = isVerifyingCode
                ) {
                    onNext()
                }
            }
            if (showAlert) {
                SimpleConfirmAlertDialog(msg = alertMsg) {
                    showAlert = false
                }
            }
        }
    }

    @Composable
    fun PasswordScreen(navController: NavController, email: String) {
        val keyboardController = LocalSoftwareKeyboardController.current

        var password by rememberSaveable { mutableStateOf("") }
        var confirmPassword by rememberSaveable { mutableStateOf("") }
        var isSigningUp by rememberSaveable { mutableStateOf(false) }
        var showAlert by rememberSaveable { mutableStateOf(false) }
        var alertMsg = ""
        val scope = rememberCoroutineScope()

        var passwordNotMatch by rememberSaveable { mutableStateOf(false) }

        val confirmPwdFocusRequester = FocusRequester()

        val onNext = {
            keyboardController?.hide()
            isSigningUp = true

            scope.launch {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    val deferred = viewModel.registerAsync(email, password)
                    try {
                        val uid = deferred.await()
                        Toast.makeText(
                            EnclusivApp.appContext,
                            getString(R.string.msg_you_have_joined), Toast.LENGTH_SHORT).show()
                        onNavigateUp()
                    } catch (e: EmailRegistered) {
                        alertMsg = getString(R.string.msg_signup_email_registered)
                        showAlert = true
                    } catch (e: Exception) {
                        alertMsg = getString(R.string.msg_abnormal_exception)
                        showAlert = true
                    } finally {
                      isSigningUp = false
                    }
                }
            }
        }

        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colors.background
        ) {
            Column(horizontalAlignment = Alignment.CenterHorizontally) {
                Spacer(Modifier.height(60.dp))
                HeadText(text = stringResource(R.string.ui_signup_decide_password))
                Spacer(Modifier.height(4.dp))
                NeckText(text = stringResource(R.string.ui_signup_fill_password_neck_text))
                Spacer(Modifier.height(20.dp))
                PasswordField(
                    enabled = !isSigningUp,
                    value = password,
                    isError = passwordNotMatch,
                    onPasswordValueChange = {
                        password = it
                        passwordNotMatch =
                            password.isNotEmpty() && confirmPassword.isNotEmpty() &&
                                    password != confirmPassword
                    },
                    modifier = Modifier
                        .fillMaxWidth(0.8F)
                        .wrapContentHeight(),
                    textStyle = TextStyle(fontSize = 16.sp),
                    onKeyBoardActionDone = {
                        confirmPwdFocusRequester.requestFocus()
                    }
                )
                Spacer(Modifier.height(10.dp))
                PasswordField(
                    enabled = !isSigningUp,
                    labelString = stringResource(R.string.ui_text_field_confirm_password),
                    value = confirmPassword,
                    isError = passwordNotMatch,
                    onPasswordValueChange = {
                        confirmPassword = it
                        passwordNotMatch =
                            password.isNotEmpty() && confirmPassword.isNotEmpty() &&
                                    password != confirmPassword
                    },
                    modifier = Modifier
                        .fillMaxWidth(0.8F)
                        .wrapContentHeight()
                        .focusRequester(confirmPwdFocusRequester),
                    textStyle = TextStyle(fontSize = 16.sp),
                    onKeyBoardActionDone = {
                        onNext()
                    }
                )
                Spacer(Modifier.height(50.dp))

                FantasticCircularButtonWithLoadingIndicator(
                    enabled = password.isNotEmpty() && confirmPassword.isNotEmpty() &&
                            password == confirmPassword && !isSigningUp,
                    size = 90.dp,
                    textStr = "JOIN",
                    textSize = 16.sp,
                    textFontWeight = FontWeight.Bold,
                    textFontStyle = FontStyle.Normal,
                    onClick = {
                        onNext()
                    },
                    isLoading = isSigningUp,
                )
            }

            if (showAlert) {
                SimpleConfirmAlertDialog(msg = alertMsg) {
                    showAlert = false
                }
            }
        }
    }
}